快速理解一個 async/await
方法被編譯後的「狀態機 + builder + awaiter」實際樣貌,並透過 C# 反編譯與 IL 片段觀察控制流程、例外、同步快速路徑與延續安排。
public static async Task<int> FetchAndParseAsync(HttpClient http, string url)
{
var html = await http.GetStringAsync(url); // await #1
await Task.Delay(10); // await #2
return html.Length;
}
[CompilerGenerated]
private sealed class <FetchAndParseAsync>d__0 : IAsyncStateMachine
{
public int <>1__state;
public AsyncTaskMethodBuilder<int> <>t__builder;
// 參數捕捉
public HttpClient http;
public string url;
// 局部變數提升
private string <html>5__2;
// awaiter 暫存
private TaskAwaiter<string> <>u__1;
private TaskAwaiter <>u__2;
void IAsyncStateMachine.MoveNext()
{
int result;
try
{
TaskAwaiter<string> a1;
TaskAwaiter a2;
switch (<>1__state)
{
case -1: // 初始
a1 = http.GetStringAsync(url).GetAwaiter();
if (!a1.IsCompleted)
{
<>1__state = 0;
<>u__1 = a1;
<>t__builder.AwaitUnsafeOnCompleted(ref a1, ref this);
return;
}
goto COMPLETE_AWAIT1;
case 0: // 從 await #1 回來
a1 = <>u__1;
<>u__1 = default;
<>1__state = -1;
goto COMPLETE_AWAIT1;
case 1: // 從 await #2 回來
a2 = <>u__2;
<>u__2 = default;
<>1__state = -1;
goto COMPLETE_AWAIT2;
}
COMPLETE_AWAIT1:
var html = a1.GetResult();
<html>5__2 = html;
a2 = Task.Delay(10).GetAwaiter();
if (!a2.IsCompleted)
{
<>1__state = 1;
<>u__2 = a2;
<>t__builder.AwaitUnsafeOnCompleted(ref a2, ref this);
return;
}
COMPLETE_AWAIT2:
a2.GetResult(); // 確認完成 / 傳播例外
result = <html>5__2.Length;
}
catch (Exception ex)
{
<>1__state = -2;
<>t__builder.SetException(ex);
return;
}
<>1__state = -2;
<>t__builder.SetResult(result);
}
void IAsyncStateMachine.SetStateMachine(IAsyncStateMachine stateMachine) =>
<>t__builder.SetStateMachine(stateMachine);
}
public static Task<int> FetchAndParseAsync(HttpClient http, string url)
{
var sm = new <FetchAndParseAsync>d__0
{
<>1__state = -1,
<>t__builder = AsyncTaskMethodBuilder<int>.Create(),
http = http,
url = url
};
sm.<>t__builder.Start(ref sm);
return sm.<>t__builder.Task;
}
重點:
<>1__state
= -1 初始;0 / 1 對應各 await 之「掛起後返回」續點。await
轉成:取 awaiter → 判斷 IsCompleted
→ 未完成則:儲存 state + AwaitUnsafeOnCompleted
+ return。GetResult()
取值或拋出例外。SetResult / SetException
結束任務。